#ifndef NET_H
#define NET_H

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>

#pragma comment(lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")

struct Returninfo
{
	int error;
	SOCKET sock;
};

Returninfo NetInit(bool server, char* servera, int port)
{
	WSAData wsadata;

	Returninfo ret;

	int res = WSAStartup(MAKEWORD(2,2), &wsadata);
	if(res != 0)
	{
		std::cout<<"WSAStartup failed: Error "<<res<<"\n";
		ret.error=1;
		return ret;
	}
	if(server)
	{
		SOCKET listen = INVALID_SOCKET;
		listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

		if(listen == INVALID_SOCKET)
		{
			std::cout<<"socket failed: Error "<<WSAGetLastError()<<"\n";
			WSACleanup();
			ret.error=3;
			return ret;
		}

		SOCKADDR_IN inf;
		inf.sin_family=AF_INET;
		inf.sin_addr.S_un.S_addr=INADDR_ANY;
		inf.sin_port=htons(port);

		res = bind(listen, (SOCKADDR*)(&inf),sizeof(inf));
		if(res == INVALID_SOCKET)
		{
			std::cout<<"bind failed: Error "<<WSAGetLastError()<<"\n";
			closesocket(listen);
			WSACleanup();
			ret.error=4;
			return ret;
		}
		ret.error=0;
		ret.sock = listen;
		return ret;
	}
	else
	{
		SOCKET sock = INVALID_SOCKET;

		sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if(sock == INVALID_SOCKET)
		{
			std::cout<<"socket failed: Error "<<WSAGetLastError()<<"\n";
			WSACleanup();
			ret.error=3;
			return ret;
		}

		hostent *host;
		host = gethostbyname(servera);

		SOCKADDR_IN SockAddr;
		SockAddr.sin_port=htons(port);
		SockAddr.sin_family=AF_INET;
		SockAddr.sin_addr.s_addr=*((unsigned long*)host->h_addr);

		res = connect(sock, (SOCKADDR*)(&SockAddr), sizeof(SockAddr));
		if(res == SOCKET_ERROR)
		{
			closesocket(sock);
			std::cout<<"connect failed\n"<<WSAGetLastError()<<"\n";
			WSACleanup();
			ret.error=4;
			return ret;
		}
		ret.error=0;
		ret.sock = sock;
		return ret;
	}
}

void NetSend(SOCKET sock, void* buf, int buflen)
{
	send(sock,(char*)buf,buflen,0);
}

void NetRecv(SOCKET sock, void* buf, int buflen)
{
	recv(sock,(char*)buf,buflen,0);
}

void NetListen(SOCKET sock, int backlog)
{
	if(listen(sock,backlog) == SOCKET_ERROR)
	{
		std::cout<<"listen failed... "<<WSAGetLastError()<<"\n";
	}
}

SOCKET NetAccept(SOCKET sock)
{
	SOCKET csock = INVALID_SOCKET;
	csock = accept(sock,NULL,NULL);
	return csock;
}

int NetCleanup(SOCKET sock)
{
	int iResult = shutdown(sock, SD_SEND);
	if (iResult == SOCKET_ERROR)
	{
		std::cout<<"shutdown failed: \n"<<WSAGetLastError();
		closesocket(sock);
		WSACleanup();
		return 1;
	}
	closesocket(sock);
	WSACleanup();

	return 0;
}

#endif